package com.vids.task;


import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vids.constant.GlobalConstant;
import com.vids.constant.Urlconstant;
import com.vids.mapper.VIIDServerMapper;
import com.vids.model.entity.Register;
import com.vids.model.entity.VIIDServer;
import com.vids.model.param.KeepaliveParam;
import com.vids.model.param.RegisterParam;
import com.vids.model.param.UnRegisterParam;
import com.vids.runner.VIIDRunner;
import com.vids.service.IBaseService;
import com.vids.utils.DegistUtils;
import com.vids.utils.QueryUtils;
import com.vids.utils.RestTemplateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author ly
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class VIIDServerTask {
   private final VIIDRunner viidRunner;
   private final IBaseService baseService;
   private final  RestTemplate restTemplate;
   private final VIIDServerMapper viidServerMapper;
   private final RedisTemplate<String, String> redisTemplate;

    @PostConstruct
    public void register() {
        log.info("开始本视图库注册" );
//1、把本级联网平台设置为在线
        String selfViidServerId = viidRunner.getSelfViidServerId();
        VIIDServer viidServer = viidServerMapper.findByVIIDServerID(selfViidServerId);
        if (viidServer != null) {
            viidServer.setLastOnlineTime(new Date());
            viidServer.setIsOnline(GlobalConstant.REGISTER_CODE);
            viidServerMapper.updateById(viidServer);
        }
        String deviceStr = redisTemplate.opsForValue().get(GlobalConstant.UNREGIST_DEVICE);
        if (CharSequenceUtil.isNotBlank(deviceStr)) {
            redisTemplate.opsForValue().set(GlobalConstant.UNREGIST_DEVICE, deviceStr.replace(selfViidServerId + ",", ""));
        }
        log.info(">>>>>>>>>>>自注册启动>>>>>>>>>>>>>！");
        //2、向上级发送注册请求

        registerAndKeepLive(1);

        //3、向下级发送注册请求
//        registerAndKeepLive_subViid(1);
    }

    @PreDestroy
    public void unRegister() {
        log.info("本视图库下线" );
        //1、把本级联网平台设置为离线
        String selfViidServerId = viidRunner.getSelfViidServerId();
        VIIDServer viidServer = viidServerMapper.findByVIIDServerID(selfViidServerId);
        if (viidServer != null) {
            viidServer.setLastOnlineTime(new Date());
            viidServer.setIsOnline(GlobalConstant.UNREGISTER_CODE);
            viidServerMapper.updateById(viidServer);
        }else {
            log.info("------------> viidServer is null" );
        }
        log.info(">>>>>>>>>>>>>>>服务注销>>>>>>>>>>>>>>>>>>>>！");

        //2、向上级发送注销请求
        registerAndKeepLive(3);
        //3、向下级发送注销请求
//        registerAndKeepLive_subViid(3);
    }

//    @Scheduled(fixedRate = 90000, initialDelay = 10000)
    public void keepLive() {
        log.info(">>>>>>>>>>>服务保活>>>>>>>>>>>>>！");
        String selfViidServerId = viidRunner.getSelfViidServerId();

        registerAndKeepLive(2);
    }

    private void registerAndKeepLive(int type) {
        try {
            String selfViidServerId = viidRunner.getSelfViidServerId();
            VIIDServer viidServer = viidServerMapper.findByVIIDServerID(selfViidServerId);
            log.info("------------>selfViidServerId=={}",selfViidServerId);

            if (!ObjectUtil.isNotNull(viidServer))
            {
                log.info("------------>viidServer is null");
            }
            if (ObjectUtil.isNotNull(viidServer) && type == 2) {
                String deviceStr = redisTemplate.opsForValue().get(GlobalConstant.UNREGIST_DEVICE);
                if (CharSequenceUtil.isNotBlank(deviceStr) && deviceStr.indexOf(selfViidServerId) != -1) {
                    log.info("{}服务已经注销不能进行保活，请先注册，VIIDServerID:{}", deviceStr, selfViidServerId);
                    return;
                }
                //设置本级在线
                baseService.updateSystemStatus(GlobalConstant.REGISTER_CODE, selfViidServerId);
                //上级联网平台，多个用,分隔
                String upServerIdStr = viidServer.getUpServerID();
                List<String> upServerIds = CharSequenceUtil.splitTrim(upServerIdStr, ",");
                for (String viidId : upServerIds) {
                    VIIDServer upViidServer = new VIIDServer();
//                    upViidServer.setVIIDServerID(viidId);
                    QueryWrapper ew = new QueryWrapper();
                    ew.eq("VIIDServerID", viidId);
                    upViidServer = viidServerMapper.selectOne(ew);
                    if (ObjectUtil.isNull(upViidServer)) {
                        log.info("#registerAndKeepLive {}不存在！", viidId);
                        continue;
                    }
                    Object obj = null;
                    Register register = new Register();
                    register.setDeviceID(selfViidServerId);
                    String url = "";
                    if (type == 1) {
                        RegisterParam param = new RegisterParam();
                        param.setRegisterObject(register);
                        obj = param;
                        url = "http://" + upViidServer.getIPAddr() + ":" + upViidServer.getPort() + Urlconstant.URL_REGISTER;
                    }
                    if (type == 2) {
                        KeepaliveParam keepaliveParam = new KeepaliveParam();
                        keepaliveParam.setKeepaliveObject(register);
                        obj = keepaliveParam;
                        url = "http://" + upViidServer.getIPAddr() + ":" + upViidServer.getPort() + Urlconstant.URL_KEEPALIVE;
                    }
                    if (type == 3) {
                        UnRegisterParam unRegisterParam = new UnRegisterParam();
                        unRegisterParam.setUnRegisterObject(register);
                        obj = unRegisterParam;
                        url = "http://" + upViidServer.getIPAddr() + ":" + upViidServer.getPort() + Urlconstant.URL_UNREGISTER;
                    }
                    ResponseEntity<String> entity;
                    if (type != 2) { //1、注册 3、注销 需要用户认证
                        String username = viidRunner.getRemoteViidUsername(viidId);
                        String password = viidRunner.getRemoteViidPassword(viidId);
                        entity = remoteRegisterAndKeepalive(obj, url, username, password);
                    } else { //2、保活
                        entity = restTemplate.exchange(url, HttpMethod.POST, RestTemplateUtils.HttpPost(selfViidServerId, obj), String.class);
                    }
                    if (entity != null && entity.getStatusCodeValue() == 201) {
                        log.info("{}：向服务{}注册，保活，注销成功！", viidId, type);
                        //说明该上级联网平台在线
                        baseService.updateSystemStatus(GlobalConstant.REGISTER_CODE, viidId);
                    } else {
                        log.info("{}：向服务{}注册，保活，注销失败！", viidId, type);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("注册保活注销失败:" + e.getMessage());
        }
        log.info("无服务注册，保活，注销！");
    }

    public ResponseEntity<String> remoteRegisterAndKeepalive(Object obj, String url, String username, String password) throws JsonProcessingException {

        String selfViid = viidRunner.getSelfViidServerId();

        ObjectMapper mapper = QueryUtils.getObjectMapperInstance("", new String[] {}, "com.vids.model",
                JsonFilter.class);//远程

        HttpHeaders header = RestTemplateUtils.setRequestHeader();
        header.set("User-Identify", selfViid);
        HttpEntity<String> httpEntity = new HttpEntity<String>(mapper.writeValueAsString(obj), header);
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                if (response.getRawStatusCode() != 401) {
                    super.handleError(response);
                }
            }
        });

        log.info("url=========>"+url);
        log.info("authHeader=========>"+ JSONUtil.toJsonStr(httpEntity));

        ResponseEntity<String> entity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
        if (entity != null && entity.getStatusCodeValue() == 401) {
            HttpHeaders headers = entity.getHeaders();
            List<String> list = headers.get("WWW-Authenticate");
            String authHeader = list.get(0);
            Map<String, String> map = getMapByKeyArray(authHeader.replaceAll("Digest ", "").split(","));
            map.put("username", username);
            map.put("uri", Urlconstant.URL_REGISTER);
            map.put("cnonce", "0a4f113b");
            map.put("nc", "00000001");
            map.put("qop", "auth");
            map.put("response", getResponse(map, password));

            String strAuthHeader = buildAuthHeader(map);
            HttpHeaders head = RestTemplateUtils.setAuthHeader(strAuthHeader);
            head.set("User-Identify", selfViid);


            HttpEntity<String> requestEntity = new HttpEntity<String>(mapper.writeValueAsString(obj), head);

            log.info("requestEntity2=========>"+ JSONUtil.toJsonStr(requestEntity));

            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity,
                String.class);
            log.info("responseEntity=========>"+ JSONUtil.toJsonStr(responseEntity));
            return responseEntity;
        }
        return null;
    }

    private String getResponse(Map<String, String> maps, String password) {
        String hA1 = DegistUtils.getMD5(maps.get("username") + ":" + maps.get("realm") + ":" + password);
        String hA2 = DegistUtils.getMD5("POST:" + maps.get("uri"));
        String source = CharSequenceUtil.format("{}:{}:{}:{}:{}:{}",hA1,maps.get("nonce"), maps.get("nc"),
                maps.get("cnonce"),maps.get("qop"),hA2);
        return DegistUtils.getMD5(source);
    }
    private String buildAuthHeader(Map<String, String> maps) {
        StringBuffer value = new StringBuffer();
        value.append("Digest username=\"").append(maps.get("username")).append("\", ").append("realm=\"")
                .append(maps.get("realm")).append("\", ").append("nonce=\"").append(maps.get("nonce")).append("\", ")
                .append("uri=\"").append(maps.get("uri")).append("\", ").append("response=\"")
                .append(maps.get("response")).append("\", ").append("opaque=\"").append(maps.get("opaque"))
                .append("\", ").append("qop=").append(maps.get("qop")).append(", ").append("nc=").append(maps.get("nc"))
                .append(", ").append("cnonce=\"").append(maps.get("cnonce")).append("\"");
        return value.toString();
    }

    public Map<String, String> getMapByKeyArray(String[] resourceStr) {
        Map<String, String> maps = new HashMap<String, String>(8);
        for (String str : resourceStr) {
            if (str.contains("realm")) {
                maps.put("realm", getValueByName(str));
            } else if (str.contains("qop")) {
                maps.put("qop", getValueByName(str));
            } else if (str.contains("nonce")) {
                maps.put("nonce", getValueByName(str));
            } else if (str.contains("opaque")) {
                maps.put("opaque", getValueByName(str));
            }
        }
        return maps;
    }
    public String getValueByName(String resourceStr) {
        return resourceStr.substring(resourceStr.indexOf("\"") + 1, resourceStr.lastIndexOf("\""));
    }

    /*
    * 注册和保活本视图的下级视图库
    * */

//    @Scheduled(fixedRate = 90000, initialDelay = 10000)
//    public void keepLive_subViid() {
//        log.info(">>>>>>>>>>>注册和服务保活本视图的下级  ChenHongBang>>>>>>>>>>>>>！");
//
//        registerAndKeepLive_subViid(2);
//    }
//
//    private void registerAndKeepLive_subViid(int type) {
//        try {
//            String selfViidServerId = viidRunner.getSelfViidServerId();
//            VIIDServer viidServer = viidServerMapper.findByVIIDServerID(selfViidServerId);
//            log.info("------------>selfViidServerId=={}",selfViidServerId);
//
//            if (!ObjectUtil.isNotNull(viidServer))
//            {
//                log.info("------------>viidServer is null");
//            }
//            if (ObjectUtil.isNotNull(viidServer))
//            {
//                String deviceStr = redisTemplate.opsForValue().get(GlobalConstant.UNREGIST_DEVICE);
//                if (CharSequenceUtil.isNotBlank(deviceStr) && deviceStr.indexOf(selfViidServerId) != -1) {
//                    log.info("{}服务已经注销不能进行保活，请先注册，VIIDServerID:{}", deviceStr, selfViidServerId);
//                    return;
//                }
//                //设置本级在线
//                baseService.updateSystemStatus(GlobalConstant.REGISTER_CODE, selfViidServerId);
//                //上级联网平台，多个用,分隔
//                String subServerIdStr = viidServer.getSubServerID();
//                List<String> subServerIds = CharSequenceUtil.splitTrim(subServerIdStr, ",");
//                for (String viidId : subServerIds) {
//                    VIIDServer subViidServer = new VIIDServer();
//                    //                    upViidServer.setVIIDServerID(viidId);
//                    QueryWrapper ew = new QueryWrapper();
//                    ew.eq("VIIDServerID", viidId);
//                    subViidServer = viidServerMapper.selectOne(ew);
//                    if (ObjectUtil.isNull(subViidServer)) {
//                        log.info("#registerAndKeepLive_subViid {}不存在！", viidId);
//                        continue;
//                    }
//                    Object obj = null;
//                    Register register = new Register();
////                    register.setDeviceID(viidId);
//                    register.setDeviceID(selfViidServerId);
//                    String url = "";
//                    if (type == 1) {
//                        RegisterParam param = new RegisterParam();
//                        param.setRegisterObject(register);
//                        obj = param;
//                        url = "http://" + subViidServer.getIPAddr() + ":" + subViidServer.getPort() + Urlconstant.URL_REGISTER;
//                    }
//                    if (type == 2) {
//                        KeepaliveParam keepaliveParam = new KeepaliveParam();
//                        keepaliveParam.setKeepaliveObject(register);
//                        obj = keepaliveParam;
//                        url = "http://" + subViidServer.getIPAddr() + ":" + subViidServer.getPort() + Urlconstant.URL_KEEPALIVE;
//                    }
//                    if (type == 3) {
//                        UnRegisterParam unRegisterParam = new UnRegisterParam();
//                        unRegisterParam.setUnRegisterObject(register);
//                        obj = unRegisterParam;
//                        url = "http://" + subViidServer.getIPAddr() + ":" + subViidServer.getPort() + Urlconstant.URL_UNREGISTER;
//                    }
//                    ResponseEntity<String> entity;
//                    if (type != 2) { //1、注册 3、注销 需要用户认证
////                        String username = viidRunner.getRemoteViidUsername(viidId);
////                        String password = viidRunner.getRemoteViidPassword(viidId);
//                        String username = viidId;
//                        String password = "12345678";
//                        entity = remoteRegisterAndKeepalive(obj, url, username, password);
//                    } else { //2、保活
//                        entity = restTemplate.exchange(url, HttpMethod.POST, RestTemplateUtils.HttpPost(selfViidServerId, obj), String.class);
//                    }
//                    if (entity != null && entity.getStatusCodeValue() == 201) {
//                        log.info("{}：向服务{}注册，保活，注销成功！", viidId, type);
//                        //说明该上级联网平台在线
//                        baseService.updateSystemStatus(GlobalConstant.REGISTER_CODE, viidId);
//                    } else {
//                        log.info("{}：向服务{}注册，保活，注销失败！", viidId, type);
//                    }
//                }
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            log.error("注册保活注销失败:" + e.getMessage());
//        }
//        log.info("无服务注册，保活，注销！");
//    }

}
